package com.example.performance;

import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

@RestController
public class APIController {
    @Value(value = "classpath:data1.json")
    private Resource resource1;
    @Value(value = "classpath:data2.json")
    private Resource resource2;
    @Value(value = "classpath:data3.json")
    private Resource resource3;
    @Value(value = "classpath:data4.json")
    private Resource resource4;
    @Value(value = "classpath:data5.json")
    private Resource resource5;
    @Value(value = "classpath:data6.json")
    private Resource resource6;
    @Value(value = "classpath:data7.json")
    private Resource resource7;
    @Value(value = "classpath:data8.json")
    private Resource resource8;
    @Value(value = "classpath:data9.json")
    private Resource resource9;
    @Value(value = "classpath:data10.json")
    private Resource resource10;

    @RequestMapping(value = "/performance/test/**")
    public Map performanceText(@RequestBody(required = false) String payload, HttpServletRequest request, HttpServletResponse response) throws Exception{
        return getMethod(payload, request, response);
    }

    @RequestMapping(value = "/performance/test/**", consumes = {"application/json", "application/xml"})
    public Map performanceJsonXml(@RequestBody(required = false) Map payload, HttpServletRequest request, HttpServletResponse response) throws Exception{
        return getMethod(payload, request, response);
    }

    private Map getMethod(Object payload, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String delay = request.getHeader("delay");
        String length = request.getHeader("content-size");
        String auth = request.getHeader("auth");
        String needContentType = request.getHeader("needContentType");
        if(!StringUtils.isEmpty(needContentType)){
            if(!needContentType.equalsIgnoreCase(request.getHeader("content-type"))){
                setPrintWriter(415, response, "API not support the Media Type:" + request.getHeader("content-type"));
                return null;
            }
        }
        boolean authFlag = (StringUtils.isEmpty(auth) ? false : true);
        if (authFlag) {
            String authorization = request.getHeader("Authorization");
            if(StringUtils.isEmpty(authorization)){
                setPrintWriter(401, response, "Authorization permission error");
                return null;
            }
            String content = authorization.trim().replaceAll("Basic", "").trim();
            byte[] asBytes = Base64.getDecoder().decode(content);
            content = new String(asBytes, "utf-8");
            String[] authArr = content.split(":");
            if (authArr.length == 2) {
                String[] realAuthArr = auth.split(":");
                if(realAuthArr[0].equals(authArr[0]) && realAuthArr[1].equals(authArr[1])){
                    //pass
                } else {
                    setPrintWriter(401, response, "Authorization permission error");
                    return null;
                }
            } else {
                setPrintWriter(401, response, "Authorization permission error");
                return null;
            }
        }
        Map paramMap = request.getParameterMap();
        Map result = new LinkedHashMap();
        if (!StringUtils.isEmpty(length)) {
            try {
                long l = Long.valueOf(length);
                result.put("randomTxt", randomString(l * 1024));
                if (Long.valueOf(delay) > 0) {
                    Thread.sleep(Long.valueOf(delay));
                }
                return result;
            } catch (NumberFormatException e) {
                result.put("errorMsg", "content-length is not a number.");
            }
        }
        result.put("method", request.getMethod());
        result.put("headers", getHeader(request));
        if (!StringUtils.isEmpty(delay)) {
            result.put("delay", delay);
        }
        if (paramMap != null && paramMap.size() != 0) {
            result.put("param", paramMap);
        }
        result.put("body", payload);
        result.put("url", request.getRequestURL().toString());
        result.put("data", getJson());
        if (result.containsKey("delay") && Long.valueOf(delay) > 0) {
            Thread.sleep(Long.valueOf(delay));
        }
        return result;
    }

    private Map getJson() throws IOException {
        Resource[] resources = new Resource[]{resource1, resource2, resource3, resource4, resource5, resource6, resource7, resource8, resource9, resource10};
        double r = Math.floor(Math.random() * 10);
        Resource res = resources[(int) r];
        BufferedReader br = new BufferedReader(new InputStreamReader(res.getInputStream()));
        StringBuffer message = new StringBuffer();
        String line;
        while ((line = br.readLine()) != null) {
            message.append(line);
        }
        String json = message.toString();
        Map map = new Gson().fromJson(json, Map.class);
        return map;
    }

    public static String randomString(long length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@!#$%^&*()_=+/?.<>:{}[]";
        Random random = new Random();
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int num = random.nextInt(85);
            buf.append(str.charAt(num));
        }
        return buf.toString();
    }

    private void setPrintWriter(int statusCode, HttpServletResponse response, String message) {
        ServletOutputStream out = null;
        try {
            response.setStatus(statusCode);
            out = response.getOutputStream();
            out.println(new Gson().toJson(message));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Map getHeader(HttpServletRequest request){
        Enumeration<String> enumeration = request.getHeaderNames();
        Map map = new LinkedHashMap();
        while (enumeration.hasMoreElements()){
            String headerName = enumeration.nextElement();
            map.put(headerName, request.getHeader(headerName));
        }
        return map;
    }
}
